#ifndef _BTL_BEP_H
#define _BTL_BEP_H

#include "btl_alg_type.h"
/***********************************************************************
 * @name    SpiSendByteFuncPtr
 * @brief   SPI写一个字节

 * @param   nByte :  [in]数据
 * @retval  			： 返回0表示成功
 * @example
int BL_SendByte(uint8_t nData)
{
    EXAMPLE_SPI_MASTER->TXCTL = 0x071D0000;
    while (!(VFIFO->SPI[0].STATSPI & VFIFO_SPI_STATSPI_TXEMPTY_MASK))
    {}
    EXAMPLE_SPI_MASTER->TXDATCTL = (nData|0x071D0000);
    while (!(EXAMPLE_SPI_MASTER->STAT & SPI_STAT_RXRDY_MASK))
    {}
    EXAMPLE_SPI_MASTER->RXDAT;
    return 0;
}
//初始化时赋值
blInitParam.spi_send_byte = BL_SendByte;
 **********************************************************************/
typedef int (*SpiSendByteFuncPtr)(unsigned char nByte);

/***********************************************************************
 * @name    SpiRevByteFuncPtr
 * @brief   SPI读数据

 * @param   rx_buffer :  [in]接受数据的buffer
 * @param   num       :  [in]要接受数据的大小
 * @retval            ： 返回0表示成功
 * @example
int BL_RecvBuffer(unsigned char *rx_buffer, const unsigned int num)
{
    unsigned int i;
    for(i = 0; i < num; i++)
    {
        EXAMPLE_SPI_MASTER->TXCTL = 0x071D0000;
        while (!(VFIFO->SPI[0].STATSPI & VFIFO_SPI_STATSPI_TXEMPTY_MASK))
        {}
        EXAMPLE_SPI_MASTER->TXDATCTL = (0x071D0000);
        while (!(EXAMPLE_SPI_MASTER->STAT & SPI_STAT_RXRDY_MASK))
        {}
        rx_buffer[i] = EXAMPLE_SPI_MASTER->RXDAT;
    }
    return 0;
}
//初始化时赋值
blInitParam.spi_rev_byte = BL_RecvBuffer;
 **********************************************************************/
typedef int (*SpiRevByteFuncPtr)(unsigned char* rx_buffer, unsigned int num);

/***********************************************************************
 * @name    RstnSetFuncPtr
 * @brief   RST脚控制

 * @param   RST_LEVEL :  [in]电平控制，0表示拉低，1表示拉高
 * @example
void RSTN_Set(uint8_t LEVEL)
{
    if(LEVEL == 1)
    {
        RSTN_High();
    }
    else
    {
        RSTN_Low();
    }
    Delay_ms(1); //如果存在翻转电路，则根据翻转电路的信号延迟适当调整
}
//初始化时赋值
blInitParam.rstn_set = RSTN_Set;
 **********************************************************************/
typedef void (*RstnSetFuncPtr)(unsigned char RST_LEVEL);

/***********************************************************************
 * @name    SpiCSSetFuncPtr
 * @brief   CS脚控制

 * @param   CS_LEVEL :  [in]电平控制，0表示拉低，1表示拉高
 * @example
void BL_CS_SET(uint8_t LEVEL)
{
        if(LEVEL == 1)
        {
            BL_CS_HIGH();
        }
        else
        {
            BL_CS_LOW();
        }
        Delay_us(5); //如果存在翻转电路，则根据翻转电路的信号延迟适当调整
}
//初始化时赋值
blInitParam.spi_cs_set = BL_CS_SET;
 **********************************************************************/
typedef void (*SpiCSSetFuncPtr)(unsigned char CS_LEVEL);
/*
延时函数
*/
typedef void (*DelayFuncPtr)(unsigned int times);


/*
工作模式枚举
*/
typedef enum {
    BTL_IDLE_MODE          = 0,  // 空闲模式
    BTL_ENROLLMENT_MODE    = 1,  // 注册模式
    BTL_VERIFY_MODE        = 2,  // 匹配模式
    BTL_GET_IMAGE_MODE     = 3,  // 采图模式
    BTL_FINGER_DETECT_MODE = 4,  // 手指检测模式
} btl_mode_t;

/*
错误码枚举
*/
typedef enum btl_bep_rc_e {
    /* 成功 */
    BTL_RC_OK = 0x00,
    /* 手指没抬起 */
    BTL_RC_FINGER_NO_UP = 0x01,
    /* 未检测到手指按压	*/
    BTL_RC_FINGER_DETECT_ERR = 0x02,
    /* 注册失败 */
    BTL_RC_ENROLLMENT_ERR = 0x03,
    /* 匹配失败 */
    BTL_RC_VERIFY_FAIL = 0x04,
    /* 采集图像失败 */
    BTL_RC_GET_IMAGE_FAIL = 0x05,
    /* 图片质量差 */
    BTL_RC_IMAGE_NG = 0x06,
    /* SPI通讯出错 */
    BTL_RC_SPI_ERR = 0x07,
    /* 抽取模板失败 */
    BTL_RC_EXTRACT_TEMPLATE_FAIL = 0x08,
    /* 合成多模板失败 */
    BTL_RC_CREATE_MULTI_TEMPLATE_FAIL = 0x09,
    /* 图像有效面积太小	*/
    BTL_RC_IMAGE_AREA_ERR = 0x0A,
    /* 手指太干（图像过黑）	*/
    BTL_RC_IMAGE_DRY_ERR = 0x0B,
    /* 手指太湿（图像过白）*/
    BTL_RC_IMAGE_HUMIDITY_ERR = 0x0C,
    /* 模板动态更新失败 */
    BTL_RC_DYNAMIC_UPDATE_ERR = 0x0D,
    /* SENSOR ID 错误	*/
    BTL_RC_SENSOR_ID_ERR = 0x0E,
    /* 内存申请失败	*/
    BTL_RC_MALLOC_ERR = 0x0F,
    /* SENSOR表面存在疑似异物 */
    BTL_RC_STATIC_PATTERN_ERR = 0x10,
    /* SENSOR表面存在疑似裂纹 */
    BTL_RC_CRACK_ERR = 0x11,
    /* 同一个模板录入多个手指 */
    BTL_RC_MULTI_FINGERS = 0x12,
    /* SENSOR异常复位, V3.2.0版本及之前为0xFC	*/
    BTL_RC_RESET_ERR = 0x13,
    /* 采图中断标记错误 */
    BTL_RC_IMAGE_STATUS_ERR = 0x14,
    /* 设备异常故障 */
    BTL_RC_DEVICE_ERR = 0x15,
    /* 输入参数错误	*/
    BTL_RC_PARAM_ERROR = 0x16,
    /* 一般错误	*/
    BTL_RC_GENERAL_ERROR = 0x17,
    /* 不支持该操作	*/
    BTL_RC_NOT_SUPPORT = 0x18,
    /* SENSOR料号错误	*/
    BTL_RC_METERIALS_ERROR = 0x19,
    /* 注册时按压位置重合度过高	*/
    BTL_RC_MUCH_OVERLAP = 0x1A,
    /* 手指重复注册 */
    BTL_RC_EXIST_ENROLL_ID = 0x1B,
    /* SENSOR存在疑似坏线 */
    BTL_RC_SENSOR_BAD_LINE_ERR = 0x1C,
    /* 录入子模板间相似度过低 */
    BTL_RC_LOW_ENROLL_SIMILARITY = 0x1D,
    /* 比对超时退出 */
    BTL_RC_VERIFY_TIMEOUT = 0x1E,
    /* 模板数据错误 */
    BTL_RC_WRONG_TEMPLATE_DATA = 0x1F,
    /* 加密初始化失败 */
    BTL_RC_CRYPT_INIT_ERR = 0x20,
    /* 加密失败 */
    BTL_RC_ENCRYPT_ERR = 0x21,
    /* 解密失败 */
    BTL_RC_DECRYPT_ERR = 0x22,
    /* MAX */
    BTL_RC_MAX = 100,  // 0x1F->100
} btl_rc_t;

/*
SENSOR ID
*/
typedef enum {
    BTL_SENSOR_ID_UNDEFINE = 0,
    BTL_SENSOR_ID_BF81192  = 0x81192,
    BTL_SENSOR_ID_BF82192  = 0x82192,
    BTL_SENSOR_ID_BF81160  = 0x81160,
    BTL_SENSOR_ID_BF82160  = 0x82160,
    BTL_SENSOR_ID_BF83160  = 0x83160,
    BTL_SENSOR_ID_BF82112  = 0x82112,
    BTL_SENSOR_ID_BF83112  = 0x83112,
    BTL_SENSOR_ID_BF81088  = 0x81088,
    BTL_SENSOR_ID_BF81072  = 0x81072,
    BTL_SENSOR_ID_BF81080  = 0x81080,
    BTL_SENSOR_ID_BF81060  = 0x81060,
    BTL_SENSOR_ID_BF82100  = 0x82100,
} btl_sensor_id_t;

/*
模组COVER类型,0x55AA作为magic数字，避免变量未初始化使用
*/
typedef enum {
    BTL_MCT_COATING  = 0x55AA0000,  // COATING
    BTL_MCT_GLASS    = 0x55AA0001,  // 玻璃
    BTL_MCT_SAPPHIRE = 0x55AA0002,  // 蓝宝石
    BTL_MCT_CERAMICS = 0x55AA0003,  // 陶瓷
} btl_module_cover_type_t;

/*
初始化参数结构体
*/
typedef struct {
    RstnSetFuncPtr rstn_set;             // SENSOR复位脚控制，如果没有控制，则赋值NULL
    SpiCSSetFuncPtr spi_cs_set;          // SPI CS脚控制
    SpiSendByteFuncPtr spi_send_byte;    // SPI字节发送
    SpiRevByteFuncPtr spi_rev_byte;      // SPI字节接收
    DelayFuncPtr delay_ms;               // 毫秒延时,精度要求[100%,150%]
    DelayFuncPtr delay_us;               // 微秒延时,精度要求[100%,200%]
    unsigned char* pImage;               // 用于存放图像数据的缓冲区地址，如果传入NULL，则由SDK内部自动申请
    btl_module_cover_type_t cover_type;  // 模组COVER类型
} BEP_INIT_PARAM;

/*
图像质量参数
*/
typedef struct {
    unsigned char nQuality;   // 图像质量，范围[0,100]，0表示最差，100表示最好
    unsigned char nArea;      // 有效面百分比，范围[0,100]
    unsigned char nConditon;  // 干湿程度，范围[0,100]，50为最佳
    unsigned char nSNR;       // added 2021/12/27
} BTL_IMAGE_QUALITY;

/*
图像质量阈值结构体
*/
typedef struct {
    unsigned char min_quality;
    unsigned char min_area;
    unsigned char min_condition;
    unsigned char max_condition;
    unsigned char min_nSNR;                  // added 2021/12/27
    unsigned char max_static_pattern_score;  // wlx added 2022/09/29
} BTL_IMAGE_QUALITY_CTRL;

/*
FD 周期设置，默认是200ms
*/
typedef enum {
    BTL_50MS_3_3V,
    BTL_100MS_3_3V,
    BTL_150MS_3_3V,
    BTL_200MS_3_3V,
    BTL_250MS_3_3V,
    BTL_300MS_3_3V,
    /* add others */
    BTL_FREQ_NUM,
} BTL_FREQUENCE_PARAM;

/*
可动态调整的配置
*/
typedef struct {
    /*
     *比对安全等级
     */
    int nFarAccepted;
    /*
     *更新模板时再次比对的安全等级
     */
    int update_FAR_level;
    /*
     *录入次数
     */
    int nEnrollCounts;
    /*
     *手指检测周期
     */
    int finger_detect_preriod;
    /*
     *注册时图像质量控制
     */
    BTL_IMAGE_QUALITY_CTRL image_quality_for_enroll;
    /*
     *匹配时图像质量控制
     */
    BTL_IMAGE_QUALITY_CTRL image_quality_for_verify;
    /*
     *检测传感器异常像素，0表示只检测坏线，大于0表示检测坏线和裂痕等，小于0表示不做任何检测
     */
    int max_crack_pixels;
    /*
     *比对超时时间，单位毫秒.设置成0表示不限制
     */
    unsigned short nVerifyTimeOut;
    /*
     *是否禁止相同位置录入，0表示不禁止，1表示禁止，默认为禁止
     */
    // unsigned char bForbidSamePos;  //用.duplicate_min_distance = 0; 实现不禁止
    /*
     *手指抬起检测功能控制，0表示关闭，非0表示打开，默认1：打开.
     */
    unsigned char FingerUpdetect;
    /*
     *图像增强功能开关，0表示关闭，非0表示打开
     */
    unsigned char ImageEnhance;
    /*
     *灵敏度调整最小值
     */
    unsigned char Dacp_min;
    /*
     *灵敏度调整最大值
     */
    unsigned char Dacp_max;
    /*
     *	bit[0]，图像修复开关，1表示打开; bit[1]，图像平滑开关，1表示打开
     */
    unsigned char image_modify_control;
    /*
     *参数自动调节控制器
     *0表示关，非0表示开
     *其中bit[1]控制GAIN调节，1表示开，0表示关
     */
    unsigned char AGC_controler;
    /*
     *	图像不合格时尝试采图次数
     */
    unsigned char re_image_cnt;
    /* 检测静态异物卡控分数，默认值为0,范围[0,100]。
     * 移到image_quality_for_enroll和image_quality_for_verify中分别设置
     */
    // unsigned char static_pattern_score;
    /*
    AGC目标灰度均值
    */
    unsigned char agc_aim_mean;
    /*
     *配置为1则通过查询寄存器方式检测中断，默认是0（中断方式）
     */
    unsigned char check_interrupt_by_query_register;
    /*
     *移到image_quality_for_enroll和image_quality_for_verify中分别设置
     */
    // unsigned char image_snr_threshold;
    /*
     *调整算法的比对速度，范围[-100,0]，
     *默认值是0,值越小，速度越快.
     *每个手指参与比对的子模板数量 = max(1,max_nbr_of_subtemplates +latency_adjustment * max_nbr_of_subtemplates/100);
     *此配置设置成小于0时，建议不要配置nVerifyTimeOut(保留默认值0)
     *此配置只对R4X和R5X算法库有效，对R11无效
     *在verify之前配置,示例 btl_get_config()->latency_adjustment = -(btl_storage_get_all_template_count()/2-10);
     */
    int latency_adjustment;
    /*
     *Log开关，每个bit对应某个log等级的开关，如bit0->log0,bit1->log1,bit2->log2....
     *0表示关，1表示开，默认为全关闭。
     *如果需要变更，请在btl_bep_init之前配置，前置条件是实现了btl_printf赋值。
     *log0——异常错误
     *log1——流程信息
     *log2——采图信息
     *log3——模板信息
     *log4——算法信息
     */
    unsigned char log_switch;
    /*
     *指定传感器型号,用于采图和算法处理分离的情况
     *0表示否，默认值是0
     *如果需要变更，请在btl_bep_init之前配置，此时.pImage要设置成NULL
     */
    btl_sensor_id_t is_specify_sensor;
} BTL_CONFIG;

/*
驱动芯片类型
*/
typedef enum { BTL_DRIVER_UNKNOWN = 0, BTL_DRIVER_NONE, BTL_DRIVER_BF2080, BTL_DRIVER_BF3080 } btl_driver_type_t;
/*
获取驱动芯片类型
*/
extern btl_driver_type_t btl_get_driver_type(void);

/*
获取可调参数结构体指针
*/
extern BTL_CONFIG* btl_get_config(void);

/*
部分算法和SENSOR参数，初始化时调整
*/
typedef struct {
    // 模板的最大字节数
    unsigned int max_template_size;
    // 是否锁定录入的模板不被替换更新，1表示锁定，0表示不锁定，默认为0(V3.0.3及之前版本默认为1)
    int lock_templates_after_enroll;
    // 是否支持360度比对，1表示支持, 0表示不支持
    unsigned char support_360rotate;
    // 防止不同手指注册进同一个ID, 默认为0
    // 0:不禁止,也不返回孤岛数
    // 1:禁止不同手指录入,且返回孤岛数
    // 2:最大孤岛录入,且返回孤岛数
    // 3:不禁止多手指录入,但返回孤岛数
    unsigned char prevent_enroll_multifingers;
    // 注册时判定为相同位置的最小偏移量，可在默认值基础上调节，建议调节范围[-10,90]
    // unsigned char duplicate_min_distance; //改由btl_set_enroll_overlap_param设置
    // 灵敏度调整参数
    unsigned char dacp_val;
    // 图像对比度调整参数1
    unsigned char reg31_val;
    // 图像对比度调整参数2
    unsigned char reg32_val;
} BTL_PARAM;

typedef struct _TEnrollOverlapParam {
    // 注册时判定为相同位置的最小偏移量，范围[0,100]
    // R5X版本这个值表示面积重合率,例如设置成30，就表示当前图像跟之前的图像重合率要小于(100-30)%才被允许
    unsigned char duplicate_min_distance;
    /** The number of templates to check if the current template is very similar too. If the
     * template is similar then it contains redundant information and may be rejected for enrollment.
     * This setting can be used to limit the number of templates to check redundancy against or even
     * disable it completely (0). Default 1 (only check against last added template).
     * only for R4X version algorithm */
    int nbr_to_check_redundancy_against;
} TEnrollOverlapParam;

/*
获取注册时的位置查重参数
*/
extern TEnrollOverlapParam btl_get_enroll_overlap_param(void);

/***********************************************************************
  * @name    btl_set_enroll_overlap_param
  * @brief   设置注册时的位置查重参数，在调用注册接口之前设置即可

  * @param   pParam       :  [in] 见结构体TEnrollOverlapParam
  * @retval  void         ：
  * @example
  TEnrollOverlapParam enroll_overlap_param;
  enroll_overlap_param = btl_get_enroll_overlap_param();
  enroll_overlap_param.duplicate_min_distance = 30;
  enroll_overlap_param.nbr_to_check_redundancy_against = 8;
  btl_set_enroll_overlap_param(&enroll_overlap_param);
 **********************************************************************/
extern void btl_set_enroll_overlap_param(TEnrollOverlapParam* pParam);

/*
获取sensor ID
*/
extern btl_sensor_id_t btl_get_sensor_id(void);
/*
获取SDK版本号
*/
extern char* btl_get_version(void);
/*
sensor中断处理（上升沿触发）,用户需要将此函数放到指纹模组的INT脚中断处理函数中
*/
extern void btl_sensor_int_handle(void);

/***********************************************************************
 * @name    btl_timer_ms_handle
 * @brief   定时处理函数，用户需要将此函数放到定时器中断处理函数中
 * @param   n      :  [in] 定时周期，单位是毫秒，如是1毫秒定时器，则n=1
 * @retval  void
 **********************************************************************/
extern void btl_timer_ms_handle(unsigned char n);

/*
init the SDK, about 4 milliseconds(include 2 milliseconds delay for reset)
*/
extern btl_rc_t btl_bep_init(BEP_INIT_PARAM* InitParam  //[in] 必选初始化参数
);

/*
资源释放，在MCU非掉电、RAM不能保持的情况下需要用到，休眠前释放资源
如果使用了btl_storage_init，则同时需要调用btl_storage_uninit()，见头文件btl_external_template_storage.h
唤醒之后调用一次btl_init_global_variables();
*/
extern void btl_bep_uninit(void);

/***********************************************************************
 * @name    btl_init_global_variables
 * @brief
初始化库中所有的全局变量和静态变量，如果MCU休眠时没法保持全局变量和静态变量的值，
则在唤醒时需要先调用此接口，然后再调用btl_bep_init。
注意每次唤醒之后只能调用一次，不然会造成内存泄漏。
***********************************************************************/
extern void btl_init_global_variables(void);

/*
获取指纹传感器与算法相关参数
*/
extern BTL_PARAM btl_get_param(void);
/*
参数设置函数指针，为了统一接口而创建，使用方法如下
btl_set_param = btl_set_param_hybrid;
*/
extern int (*btl_set_param)(const BTL_PARAM*);

/*
配置指纹传感器与算法相关参数
*/
// 内存资源需求较低，模板提取最慢，模板搜索最快，拒真率较低
extern int btl_set_param_hybrid(const BTL_PARAM* param);
// 内存资源需求最大，模板提取较快，模板搜索较快，拒真率最低
extern int btl_set_param_cardo(const BTL_PARAM* param);
// 仅支持112系列，节省代码空间
extern int btl_set_param_cardo_112only(const BTL_PARAM* param);
// 内存资源需求最低，模板提取最快，模板搜索最慢，拒真率最高
extern int btl_set_param_spectral(const BTL_PARAM* param);

/*
设置是否开启360度比对，在btl_set_param之后调用才有效
*/
extern int btl_set_feature_360(unsigned char bOpen360  // 1表示开启，0表示关闭
);

/*
模板容量的独立设置接口
*/
extern void btl_set_max_template_size(unsigned int nMaxTemplateSize);

/*
获取当前工作模式
*/
extern btl_mode_t btl_get_work_mode(void);

/*
设置工作模式
返回值：
BTL_RC_OK —— 表示设置成功
other —— 表示设置失败
*/
extern btl_rc_t btl_set_work_mode(btl_mode_t mode);

/*
检测手指按压、采图、预处理等，新接口，搭配btl_set_work_mode使用，替代旧的接口btl_finger_detect
替代方案如下：
1、需要切换模式的地方，使用btl_set_work_mode替换btl_finger_detect
2、需要检测手指和采图的地方，使用btl_finger_detect_ex替换btl_finger_detect
返回值：
  BTL_IDLE_MODE
    总是返回 BTL_RC_FINGER_DETECT_ERR
  BTL_ENROLLMENT_MODE
  BTL_VERIFY_MODE
  BTL_GET_IMAGE_MODE
    返回 BTL_RC_OK 表示采集到合格图像
  BTL_FINGER_DETECT_MODE
    返回BTL_RC_OK 表示检测到手指按压
    返回BTL_RC_FINGER_DETECT_ERR 表示未检测到手指
*/
extern btl_rc_t btl_finger_detect_ex(void);

/*
工作模式切换、检测手指按压、采图、预处理等，旧接口
*/
extern btl_rc_t btl_finger_detect(btl_mode_t mode);

/*
注册指纹，最终获取的指纹数据需要用户主动释放
*/
extern btl_rc_t btl_enrollment(int* pAcceptedNum,               //[out] 已录入次数，如果函数返回OK，但是次数没有增加，则表示按压位置重复
                               int* island_num,                 //[out] 孤岛数，非必须，只有prevent_enroll_multifingers为非0的时候才会返回
                               PBL_TEMPLATE pbtlMultiTemplates  //[out] 注册完成模板,当pAcceptedNum等于设置的录入次数时才有效，注意：用户一定要及时释放
);

/*
匹配，使用统一的安全等级
*/
extern btl_rc_t btl_verify(PBL_TEMPLATE blMultiTemplatesArray[],  //[in] 待匹配模板数组
                           int nNbrOfMultiTemplates,              //[in] 数组大小
                           int* pMatchIndex                       //[out] 匹配成功的模板序号
);

/***********************************************************************
  * @name    btl_extract_template
  * @brief   提取比对模板，返回模板的地址，模板由SDK内部管理，用户不要去释放

  * @param   ppbtlTemplate       :  [out] 返回模板地址，用户不需要释放此模板，如需要备份，则需另外申请缓存拷贝过去
  * @retval  btl_rc_t    ：
  * @example
  BL_TEMPLATE* subtemplate = NULL;
  btl_extract_template(&subtemplate);
  if(NULL!=subtemplate)
  {
      //使用subtemplate
  }
 **********************************************************************/
extern btl_rc_t btl_extract_template(PBL_TEMPLATE* ppbtlTemplate);

/***********************************************************************
  * @name    btl_insert_template
  * @brief   插入比对模板，如果原先比对模板已经存在，将会被替换

  * @param   pbtlTemplate       :  [in]要插入的比对模板（子模板）
  * @retval  btl_rc_t    ：
  * @example

 **********************************************************************/
extern btl_rc_t btl_insert_template(const PBL_TEMPLATE pbtlTemplate);

/***********************************************************************
  * @name    btl_create_multitemplate
  * @brief   使用已经存在的多个子模板合成一个多模板，合成模板需要用户主动释放

  * @param   pblTemplates       :  [in] 待合并指纹子模板
  * @param   nNbrOfTemplates    :  [in] 待合并指纹子模板数量
  * @param   island_num         :  [out] 合并后的孤岛个数，2个孤岛即表示有两块区域没有连接到一起
  * @param   pblMultiTemplates  :  [out] 合并后的多模板数组，注意：用户一定要及时释放，否则可能引起内存错乱等未知错误
  * @retval  btl_rc_t    ：
  * @example
  btl_rc_t retval = BTL_RC_OK;
  BL_TEMPLATE blMutilTemplate = {0};
  retval = btl_create_multitemplate(subtemplate_array, subtemplate_count, NULL, &blMutilTemplate);
  if(blMutilTemplate.pTemplateData && blMutilTemplate.templateSize > 0)
  {
    //多模板合成成功
  }
  btl_delete_template(&blMutilTemplate);
 **********************************************************************/
extern btl_rc_t btl_create_multitemplate(const PBL_TEMPLATE pblTemplates[], unsigned char nNbrOfTemplates, int* island_num, PBL_TEMPLATE pblMultiTemplates);

/***********************************************************************
  * @name    btl_dynamic_update_templates
  * @brief   模板比对成功之后，调用此函数进行模板更新

  * @param   pblMultiTemplates       :  [in]匹配成功的模板
  * @param   pblUpdateMultiTemplates :  [out]更新后的指纹模板，更新成功即可存入flash中，需要用户释放
  * @retval  btl_rc_t    ：
  * @example
  BL_TEMPLATE blUpdateMultiTemplates = {0};
  retval = btl_dynamic_update_templates(&pblMultiTemplates,&blUpdateMultiTemplates);
  if(BTL_RC_OK == retval && NULL!=blUpdateMultiTemplates.pTemplateData)
  {
    //blUpdateMultiTemplates
  }
  btl_delete_template(&blUpdateMultiTemplates);
 **********************************************************************/
extern btl_rc_t btl_dynamic_update_templates(const PBL_TEMPLATE pblMultiTemplates, PBL_TEMPLATE pblUpdateMultiTemplates);

/*
释放指纹模板数据所占缓存
*/
extern void btl_delete_template(PBL_TEMPLATE pbtlTemplate  //[in] 待释放的指纹模板
);

/*
获取图像数据接口，返回图像数据buffer地址
*/
extern unsigned char* btl_get_image_data(void);

/*
获取图像的宽度
*/
extern int btl_get_image_width(void);

/*
获取图像的高度
*/
extern int btl_get_image_height(void);

/*
获取图像质量
*/
extern BTL_IMAGE_QUALITY btl_get_image_quality(void);

/***********************************************************************
 * @name    btl_outside_image_preproc_1
 * @brief   支持传入外部图像预处理接口，对原始图像进行预处理，
在图像质量计算之前执行，此接口不受btl_get_config()->ImageEnhance控制

 * @param   image   :  [in] 原始图像数据
 * @param   w       :  [in] 图像宽
 * @param   h       :  [in] 图像高
 * @retval  int     ： 0表示成功，else表示失败
 **********************************************************************/
extern int (*btl_outside_image_preproc_1)(unsigned char* image, int w, int h);

/***********************************************************************
 * @name    btl_outside_image_preproc_2
 * @brief   支持传入外部图像预处理接口，对原始图像进行预处理，
在图像质量计算之后执行，此接口不受btl_get_config()->ImageEnhance控制

 * @param   image   :  [in] 原始图像数据
 * @param   w       :  [in] 图像宽
 * @param   h       :  [in] 图像高
 * @retval  int     ： 0表示成功，else表示失败
 **********************************************************************/
extern int (*btl_outside_image_preproc_2)(unsigned char* image, int w, int h);

extern int btl_cardo_ImageEnhance(unsigned char* image, int w, int h);

/***********************************************************************
 * @name    btl_customer_run_interleaved
 * @brief
 *  比对过程中的回调函数,当比对过程需要关闭定时器中断时，可通过在此接口中计数来实现比对超时
 *  每个子模板会调用两次此回调函数，第一次是排序时，第二次是精确比对时
 * @param   void
 * @retval  int：返回1则中断比对，返回0则继续
 * @example
int customer_run_interleaved(void)
{
  btl_timer_ms_handle(5);//通过这个输入参数来校准timeout时间
  return 0;
}
//SDK初始化时对回调函数赋值
btl_customer_run_interleaved = customer_run_interleaved;
***********************************************************************/
extern int (*btl_customer_run_interleaved)(void);
/*************************************************************************************************/
#endif
